
#include "Color.hpp"
#include <cmath>

#define _TSOC_SSE_
#define _TSOC_SSE4_


#ifdef _TSOC_SSE_
#warning "Warning: Using SSE Instrinsics"
#include <xmmintrin.h>
#include <pmmintrin.h>
#endif

#ifdef _TSOC_SSE4_
#warning "Warning: Using SSE4 Instrinsics"
#include <smmintrin.h>
#endif

using namespace std;

namespace com
{
	namespace toxiclabs
	{
		namespace tsoc
		{
				
			
			Color::Color()
			{
				
			}
			
			Color::Color(uint32_t pixel)
			{
				float f = 1.0f/256.0f;
				
				r = f*((pixel & 0xFF000000)>>24);
				g = f*((pixel & 0x00FF0000)>>16);
				b = f*((pixel & 0x0000FF00)>>8);
				a = f*((pixel & 0x000000FF));
			}
			
			Color::Color(float r,float g,float b,float a)
			{
				Set(r,g,b,a);
			}
			
			
			Color::Color(float k)
			{
				k=k/100.0f;
					
				//red
				if(k<66.0f)
				{
					r=255.0f;
				}
				else
				{
					r=k-60.0f;
					r=329.698727446f * pow(r,-0.1332047592f);
				}
				
				//green
				if(k<=66.0f)
				{
					g=k;
					g=99.4708025861f*log(g) - 161.1195681661f;
				}
				else
				{
					g=k-60.0f;
					g=288.1221695283f * pow(g,-0.0755148492f);
				}
				
				//blue
				if(k>=66.0f)
				{
					b=255.0f;
				}
				else
				{
					if(k<=19.0f)
					{
						b=0.0f;
					}
					else
					{
						b=k-10.0f;
						b=138.5177312231f*log(b)-305.0447927307f;
					}
				}
				
				r=r/256.0f;
				g=g/256.0f;
				b=b/256.0f;
				a=1.0f;
				
				Clamp();
				
			}
			
			void Color::Set(float r,float g,float b,float a)
			{
				this->r=r;
				this->g=g;
				this->b=b;
				this->a=a;
			}
			
			void Color::Clamp()
			{
				#ifdef _TSOC_SSE_
					const float max[]={1.0f,1.0f,1.0f,1.0f};
					const float min[]={0.0f,0.0f,0.0f,0.0f};
					
					__m128 A;
					__m128 B;
					__m128 R;
					A=_mm_loadu_ps(min);
					B=_mm_loadu_ps(data);
					R=_mm_max_ps(A,B);
					
					A=_mm_loadu_ps(max);
					R=_mm_min_ps(A,R);
					
					_mm_storeu_ps(data,R);
				
				#else
				
					if(data[0]<0.0f)data[0]=0.0f;
					if(data[1]<0.0f)data[1]=0.0f;
					if(data[2]<0.0f)data[2]=0.0f;
					if(data[3]<0.0f)data[3]=0.0f;
					
					if(data[0]>1.0f)data[0]=1.0f;
					if(data[1]>1.0f)data[1]=1.0f;
					if(data[2]>1.0f)data[2]=1.0f;
					if(data[3]>1.0f)data[3]=1.0f;
				#endif
			}
			
			Color Color::Mix(Color & a)
			{
				Color c;
				
				c.r=(this->r+a.r)*0.5f;
				c.g=(this->g+a.g)*0.5f;
				c.b=(this->b+a.b)*0.5f;
				c.a=(this->a+a.a)*0.5f;
				
				return c;
			}
			
			float& Color::operator[] (int n)
			{
				return data[n];
			}
			
			uint32_t Color::Pixel()
			{
				uint32_t pixel;
				int R,G,B,A;
				
				Clamp();
				
				R=r*255.0f;
				G=g*255.0f;
				B=b*255.0f;
				A=a*255.0f;
				
				pixel = (R<<24) | (G<<16) | (B<<8) | A;
				
				return pixel;
			}
			
			Color operator+(Color a,Color &b)
			{
				#ifdef _TSOC_SSE_
					Color c;
				
					__m128 A;
					__m128 B;
					__m128 R;
					A=_mm_loadu_ps(a.data);
					B=_mm_loadu_ps(b.data);
					R=_mm_add_ps(A,B);
					_mm_storeu_ps(c.data,R);
				
					return c;
				#else
					Color c(a.r+b.r,a.g+b.g,a.b+b.b,a.a+b.a);
					return c;
				#endif
			}
			
			Color operator-(Color a,Color &b)
			{
				Color c(a.r-b.r,a.g-b.g,a.b-b.b,a.a-b.a);
				return c;
			}
			
			Color operator*(Color a,float factor)
			{
				Color c(a.r*factor,a.g*factor,a.b*factor,a.a*factor);
				return c;
			}
			
			Color operator*(Color a,Color &b)
			{
				Color c(a.r*b.r,a.g*b.g,a.b*b.b,a.a*b.a);
				return c;
			}
		}
	}
}
